home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1998 July / EnigmA AMIGA RUN 29 (1998)(G.R. Edizioni)(IT)[!][issue 1998-07 & 08].iso / earcd / utils / datatypes / mpegsdt013.lha / dispatch.c < prev    next >
C/C++ Source or Header  |  1998-02-05  |  81KB  |  2,443 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 1.3 (5.2.98)
  5. **  mpegsystem.datatype 1.3
  6. **
  7. **  Dispatch routine for a DataTypes class
  8. **
  9. **  Written 1997/1998 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* main includes */
  15. #include "classbase.h"
  16. #include "classdata.h"
  17.  
  18. /*****************************************************************************/
  19.  
  20. /* is animation.datatype V41 ? */
  21. #define ISV41 ((cb -> cb_SuperClassBase -> lib_Version) == 41U)
  22.  
  23. /*****************************************************************************/
  24. /* local prototypes */
  25.  
  26. /* virtual demux fs-handler related */
  27. DISPATCHERFLAGS static void     Handler( void );
  28.                 static void     RunHandler( struct ClassBase *cb, struct MPEGSystemInstData *msid );
  29.                 static void     KillHandler( struct ClassBase *cb, struct MPEGSystemInstData *msid );
  30.                 static void     dispatch_packet( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct DosPacket *dp );
  31.                 static BPTR     GetStreamLock( struct ClassBase *cb, struct MPEGSystemInstData *msid, ULONG num, BOOL isaudio );
  32.                 static void     FreeLock( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct FileLock *fl );
  33.  
  34.                 static void     STRPTR2BSTR( STRPTR s );
  35.  
  36. /* MPEG system stream demultiplexer related */
  37.                 static UBYTE   *get_buf_data ( struct ClassBase *cb, struct MPEGSystemInstData *msid, long read_len );
  38.                 static UBYTE   *calc_time_stamp ( struct ClassBase *cb, struct MPEGSystemInstData *msid, UBYTE *buf_ptr , long *time_stamp );
  39.                 static UBYTE    get_next_start_code ( struct ClassBase *cb, struct MPEGSystemInstData *msid );
  40.                 static void     read_pack_header ( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACK_header *pki );
  41.                 static void     read_system_header ( struct ClassBase *cb, struct MPEGSystemInstData *msid, SYSTEM_header *si );
  42.                 static void     read_packet_header ( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACKET_header *pi );
  43.                 static void     print_pack_header ( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACK_header *pki );
  44.                 static void     print_system_header ( struct ClassBase *cb, struct MPEGSystemInstData *msid, SYSTEM_header *si );
  45.                 static void     print_packet_header ( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACKET_header *pi );
  46.  
  47.                 static void     exitdemux( struct ClassBase *cb, struct MPEGSystemInstData *msid, LONG result, LONG result2 );
  48.                 static void     demux( struct ClassBase *cb, struct MPEGSystemInstData *msid, BPTR file );
  49.  
  50. /* class related */
  51.                 static STRPTR   GetPrefsVar( struct ClassBase *, STRPTR );
  52.                 static BOOL     matchstr( struct ClassBase *, STRPTR, STRPTR );
  53.                 static void     ReadENVPrefs( struct ClassBase *, struct MPEGSystemInstData * );
  54.                 static LONG     LoadFrames( struct ClassBase *, Object * );
  55.                 static void     OpenLogfile( struct ClassBase *, struct MPEGSystemInstData * );
  56.                 static void     mysprintf( struct ClassBase *, STRPTR, STRPTR, ... );
  57.                 static void     verbose_printf( struct ClassBase *, struct MPEGSystemInstData *, STRPTR, ... );
  58.                 static void     error_printf( struct ClassBase *, struct MPEGSystemInstData *, STRPTR, ... );
  59.                 static void     syntax_printf( struct ClassBase *, struct MPEGSystemInstData *, STRPTR, ... );
  60.                 static void     debug_printf( struct ClassBase *, struct MPEGSystemInstData *, STRPTR, ... );
  61.  
  62.                 static ULONG    SaveMPEGSystem( struct ClassBase *cb, struct IClass *cl, Object *o, struct dtWrite *dtw );
  63.  
  64. /*****************************************************************************/
  65.  
  66. /* Create "mpegsystem.datatype" BOOPSI class */
  67. struct IClass *initClass( struct ClassBase *cb )
  68. {
  69.     struct IClass *cl;
  70.  
  71.     /* Create our class... */
  72.     if( cl = MakeClass( MPEGSYSTEMDTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct MPEGSystemInstData ), 0UL ) )
  73.     {
  74. #define DTSTACKSIZE (16384UL)
  75.       cl -> cl_Dispatcher . h_Entry    = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
  76.       cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch;          /* see stackswap.c */
  77.       cl -> cl_Dispatcher . h_Data     = (APTR)DTSTACKSIZE;           /* see stackswap.c */
  78.       cl -> cl_UserData                = (ULONG)cb;
  79.  
  80.       AddClass( cl );
  81.     }
  82.  
  83.     return( cl );
  84. }
  85.  
  86. /*****************************************************************************/
  87.  
  88. /* class dispatcher */
  89. DISPATCHERFLAGS
  90. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  91. {
  92.     struct ClassBase           *cb = (struct ClassBase *)(cl -> cl_UserData);
  93.     struct MPEGSystemInstData  *msid;
  94.     ULONG                       retval = 0UL;
  95.  
  96.     switch( msg -> MethodID )
  97.     {
  98. /****** mpegsystem.datatype/OM_NEW *******************************************
  99. *
  100. *    NAME
  101. *        OM_NEW -- Create a mpegsystem.datatype object.
  102. *
  103. *    FUNCTION
  104. *        The OM_NEW method is used to create an instance of the
  105. *        mpegsystem.datatype class.  This method is passed to the superclass
  106. *        first. After this, mpegsystem.datatype parses the prefs file and 
  107. *        makes a scan through the system stream to get index information 
  108. *        about the single system stream packets.
  109. *        After all, the mpegsystem.datatype starts two objects which reads
  110. *        the single video and audio streams trougth an internal
  111. *        "demultiplexer" (system stream splitter) filesystem.
  112. *
  113. *        Subclasses of mpegsystem.datatype are not supported. Any attempt to
  114. *        create a subclass object of mpegsystem.datatype will be rejected by
  115. *        this method.
  116. *
  117. *    ATTRIBUTES
  118. *        The following attributes can be specified at creation time.
  119. *
  120. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  121. *            attribute. Only DTST_FILE is supported.
  122. *            If any other type was set in a given DTA_SourceType,
  123. *            OM_NEW will be rejected.
  124. *            Defaults to DTST_FILE.
  125. *
  126. *        DTA_Handle -- For DTST_FILE, a BPTR filehandle is expected. This
  127. *            handle will be created by datatypesclass depeding on the DTF_#?
  128. *            flag, which is DTF_BINARY here.  DTST_FILE, datatypesclass
  129. *            creates a file handle from the given DTA_Name and DTA_Handle
  130. *            (a BPTR returned by Lock).
  131. *            A DTST_RAM (create empty object) source type requires a NULL
  132. *            handle.
  133. *
  134. *    RESULT
  135. *        If the object was created a pointer to the object is returned,
  136. *        otherwise NULL is returned.
  137. *
  138. ******************************************************************************
  139. *
  140. */
  141.       case OM_NEW:
  142.       {
  143.           struct TagItem *ti;
  144.  
  145.           /* We only support DTST_FILE or DTST_RAM as source type */
  146.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  147.           {
  148.             if( ((ti -> ti_Data) != DTST_FILE)
  149. #ifdef HAS_ENCODER
  150. && ((ti -> ti_Data) != DTST_RAM)
  151. #endif /* HAS_ENCODER */
  152.  )
  153.             {
  154.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  155.  
  156.               break;
  157.             }
  158.           }
  159.  
  160. #ifndef HAS_ENCODER
  161.           /* This must not be a subclass of mpegsystem.datatype
  162.            * (not implemented yet)
  163.            */
  164.           if( o == (Object *)cl )
  165. #endif /* !HAS_ENCODER */
  166.           {
  167.             if( retval = DoSuperMethodA( cl, o, msg ) )
  168.             {
  169.               LONG error;
  170.  
  171.               /* Load frames... */
  172.               if( error = LoadFrames( cb, (Object *)retval ) )
  173.               {
  174.                 /* Something went fatally wrong, dispose object */
  175.                 CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  176.                 retval = 0UL;
  177.               }
  178.  
  179.               SetIoErr( error );
  180.             }
  181.           }
  182. #ifndef HAS_ENCODER
  183.           else
  184.           {
  185.             /* Subclasses of mpegsystem.datatype are not implemented */
  186.             SetIoErr( ERROR_NOT_IMPLEMENTED );
  187.           }
  188. #endif /* !HAS_ENCODER */
  189.       }
  190.           break;
  191.  
  192. /****** mpegsystem.datatype/OM_DISPOSE ***************************************
  193. *
  194. *    NAME
  195. *        OM_DISPOSE -- Delete a mpegsystem.datatype object.
  196. *
  197. *    FUNCTION
  198. *        The OM_DISPOSE method is used to delete an instance of the
  199. *        mpegsystem.datatype class. This method is passed to the superclass
  200. *        when it has completed.
  201. *
  202. *    RESULT
  203. *        The object is deleted. 0UL is returned.
  204. *
  205. ******************************************************************************
  206. *
  207. */
  208.       case OM_DISPOSE:
  209.       {
  210.           LONG saved_ioerr = IoErr(); /* Preserve I/O error */
  211.  
  212.           /* Get a pointer to our object data */
  213.           msid = (struct MPEGSystemInstData *)INST_DATA( cl, o );
  214.  
  215.           /* Wait for any outstanding blitter usage (which may use one of our bitmaps) */
  216.           WaitBlit();
  217.  
  218.           /* Dispose the current audio and video objects */
  219.           DisposeDTObject( (msid -> msid_CurrVideo) );
  220.           DisposeDTObject( (msid -> msid_CurrAudio) );
  221.  
  222.           /* Kill our virtual demux handler */
  223.           KillHandler( cb, msid );
  224.  
  225.           /* Delete the frame pool */
  226.           DeletePool( (msid -> msid_Pool) );
  227.  
  228.           /* Close verbose output file */
  229.           if( msid -> msid_VerboseOutput )
  230.           {
  231.             Close( (msid -> msid_VerboseOutput) );
  232.           }
  233.  
  234.           /* Dispose object */
  235.           DoSuperMethodA( cl, o, msg );
  236.  
  237.           /* Restore I/O error */
  238.           SetIoErr( saved_ioerr );
  239.       }
  240.           break;
  241.  
  242.       case OM_UPDATE:
  243.       {
  244.           if( DoMethod( o, ICM_CHECKLOOP ) )
  245.           {
  246.             break;
  247.           }
  248.       }
  249.       case OM_SET:
  250.       {
  251.           /* Pass the attributes to the animation class and force a refresh if we need it */
  252.           if( retval = DoSuperMethodA( cl, o, msg ) )
  253.           {
  254. /* The following statement is commented out because mpegsystem.datatype does not allow
  255.  * subclasses when the executable was compiled without the HAS_ENCODER define. Thus, the
  256.  * following statement is NOP unless subclasses are supported...
  257.  */
  258. #ifdef HAS_ENCODER
  259.             /* Top instance ? */
  260.             if( OCLASS( o ) == cl )
  261. #endif /* HAS_ENCODER */
  262.             {
  263.               struct RastPort *rp;
  264.  
  265.               /* Get a pointer to the rastport */
  266.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  267.               {
  268.                 struct gpRender gpr;
  269.  
  270.                 /* Force a redraw */
  271.                 gpr . MethodID   = GM_RENDER;
  272.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  273.                 gpr . gpr_RPort  = rp;
  274.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  275.  
  276.                 DoMethodA( o, (Msg)(&gpr) );
  277.  
  278.                 /* Release the temporary rastport */
  279.                 ReleaseGIRPort( rp );
  280.  
  281.                 /* We did an update... */
  282.                 retval = 0UL;
  283.               }
  284.             }
  285.           }
  286.       }
  287.           break;
  288.  
  289. /****** mpegsystem.datatype/DTM_WRITE *******************************************
  290. *
  291. *    NAME
  292. *        DTM_WRITE -- Save data
  293. *
  294. *    FUNCTION
  295. *        This method saves the object's contents to disk.
  296. *
  297. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  298. *        superclass, animation.datatype, which writes a single IFF ILBM
  299. *        picture.
  300. *
  301. *        If dtw_mode is DTWM_RAW, the object saved an MPEG System stream to
  302. *        the filehandle given, starting with the current frame until
  303. *        the end is reached.
  304. *        The sequence saved can be controlled by the ADTA_Frame, ADTA_Frames
  305. *        and ADTA_FrameIncrement attributes (see TAGS section below).
  306. *
  307. *    TAGS
  308. *        When writing the local ("raw") format, MPEG System movie, the
  309. *        following attributes are recognized:
  310. *
  311. *        ADTA_Frame (ULONG) - start frame, saving starts here.
  312. *            Defaults to the current frame displayed.
  313. *
  314. *        ADTA_Frames (ULONG) - the number of frames to be saved,
  315. *            Defaults to (max_num_of_frames - curr_frame).
  316. *
  317. *        ADTA_FrameIncrement (ULONG) - frame increment when saving.
  318. *            Defaults to 1, which means: "jump to next frame".
  319. *
  320. *    NOTE
  321. *        This function is not implemented yet. A possible implementation 
  322. *        would implement ACTION_WRITE in the virtial implementation and uses
  323. *        mpegvideo.datatype and mpegaudio.datatype encoders...
  324. *
  325. *    RESULT
  326. *        Returns 0 for failure (IoErr() returns result2), non-zero
  327. *        for success.
  328. *
  329. ******************************************************************************
  330. *
  331. */
  332.       case DTM_WRITE:
  333.       {
  334.           struct dtWrite *dtw;
  335.  
  336.           dtw = (struct dtWrite *)msg;
  337.  
  338.           /* Local data format not supported yet... */
  339.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  340.           {
  341.             retval = SaveMPEGSystem( cb, cl, o, dtw );
  342.           }
  343.           else
  344.           {
  345.             /* Pass msg to superclass (which writes a single frame as an IFF ILBM picture)... */
  346.             retval = DoSuperMethodA( cl, o, msg );
  347.           }
  348.       }
  349.           break;
  350.  
  351.  
  352. /****** mpegsystem.datatype/ADTM_LOADFRAME ***********************************
  353. *
  354. *    NAME
  355. *        ADTM_LOADFRAME -- Load frame
  356. *
  357. *    FUNCTION
  358. *        The ADTM_LOADFRAME method is used to obtain the bitmap and timing
  359. *        data of the animation.
  360. *        The method is passed to the embedded mpegvideo.datatype object.
  361. *        If successfull, the sample data of struct adtFrame are replaced
  362. *        by the corresponsing audio data from the embedded 
  363. *        mpegaudio.datatype object.
  364. *
  365. *    RESULT
  366. *        Returns the result from the embedded mpegvideo.datatype object
  367. *        (including Result2).
  368. *
  369. ******************************************************************************
  370. *
  371. */
  372.       case ADTM_LOADFRAME:
  373.       {
  374.           struct adtFrame *alf = (struct adtFrame *)msg;
  375.  
  376.           /* Get a pointer to our object data */
  377.           msid = (struct MPEGSystemInstData *)INST_DATA( cl, o );
  378.  
  379.           if( msid -> msid_CurrVideo )
  380.           {
  381.             if( retval = DoMethodA( (msid -> msid_CurrVideo), msg ) )
  382.             {
  383.               /* Add here the audio part..
  384.                * A better way would be to send SDTM_LOADSAMPLE to load the sample
  385.                * fragment
  386.                */
  387.               if( msid -> msid_Sample )
  388.               {
  389.                 UBYTE *sample        = msid -> msid_Sample;
  390.                 ULONG  sample_offset = (alf -> alf_Frame)            * (msid -> msid_SamplesPerFrame);
  391.                 ULONG  len           = ((alf -> alf_Duration) + 1UL) * (msid -> msid_SamplesPerFrame);
  392.  
  393.                 /* Sample completely out-of-range ? */
  394.                 if( sample_offset >= (msid -> msid_SampleLength) )
  395.                 {
  396.                   /* No sample data ! */
  397.                   sample        = NULL;
  398.                   sample_offset = 0UL;
  399.                   len           = 0UL;
  400.                 }
  401.                 else
  402.                 {
  403.                   /* Sample partial out of range ? */
  404.                   if( (sample_offset + len) > (msid -> msid_SampleLength) )
  405.                   {
  406.                     /* Cut it ! */
  407.                     len -= ((sample_offset + len) - (msid -> msid_SampleLength));
  408.                   }
  409.                 }
  410.  
  411.                 /* Fill in the message body */
  412.                 alf -> alf_Sample       = sample + sample_offset;
  413.                 alf -> alf_SampleLength = len;
  414.                 alf -> alf_Period       = msid -> msid_Period;
  415.               }
  416.             }
  417.           }
  418.           else
  419.           {
  420.             /* No mpegvideo.datatype object (Should not occur, but...). */
  421.             SetIoErr( ERROR_OBJECT_NOT_FOUND );
  422.           }
  423.       }
  424.           break;
  425.  
  426. /****** mpegsystem.datatype/ADTM_UNLOADFRAME ************************************
  427. *
  428. *    NAME
  429. *        ADTM_UNLOADFRAME -- Unload frame contents
  430. *
  431. *    FUNCTION
  432. *        The ADTM_UNLOADFRAME method is used to release the contents of a
  433. *        animation frame.
  434. *
  435. *        This method is passed to the embedded mpegvideo.datatype object.
  436. *
  437. *    RESULT
  438. *        Returns the result from the embedded mpegvideo.datatype object.
  439. *
  440. ******************************************************************************
  441. *
  442. */
  443.       case ADTM_UNLOADFRAME:
  444.       {
  445.           /* Get a pointer to our object data */
  446.           msid = (struct MPEGSystemInstData *)INST_DATA( cl, o );
  447.  
  448.           if( msid -> msid_CurrVideo )
  449.           {
  450.             retval = DoMethodA( (msid -> msid_CurrVideo), msg );
  451.  
  452.             /* Here we should do an SDTM_UNLOADSAMPLE if the sample data were
  453.              * obtained using SDTM_LOADSAMPLE
  454.              */
  455.           }
  456.       }
  457.           break;
  458.  
  459.       /* Let the superclass handle everything else */
  460.       default:
  461.       {
  462.           retval = DoSuperMethodA( cl, o, msg );
  463.       }
  464.           break;
  465.     }
  466.  
  467.     return( retval );
  468. }
  469.  
  470.  
  471. /****** mpegsystem.datatype/preferences *****************************************
  472. *
  473. *   NAME
  474. *       preferences
  475. *
  476. *   DESCRIPTION
  477. *       The "ENV:Classes/DataTypes/mpegsystem.prefs" file contains global
  478. *       settings for the datatype.
  479. *       The preferences file is an ASCII file containing one line where the
  480. *       preferences can be set.
  481. *       It can be superset by a local variable with the same name.
  482. *
  483. *       Each line can contain settings, special settings for some projects
  484. *       can be set using the MATCHPROJECT option.
  485. *       Lines beginning with a '#' or ';' chars are treated as comments.
  486. *       Lines are limitted to 256 chars.
  487. *
  488. *   TEMPLATE
  489. *       MATCHPROJECT/K,VERBOSE/S,VERBOSESYNTAX/S,NOVERBOSESYNTAX/S,
  490. *       VERBOSEDEBUG=DEBUG/S,NOVERBOSEDEBUG=NODEBUG/S,IGNOREERRORS/S,
  491. *       NOIGNOREERRORS/S
  492. *
  493. *       MATCHPROJECT -- The settings in this line belongs only to this
  494. *           project(s), e.g. if the case-insensitive pattern does not match,
  495. *           this line is ignored.
  496. *           The maximum length of the pattern is 128 chars.
  497. *           Defaults to #?, which matches any project.
  498. *
  499. *       VERBOSE -- Print information about the animation. Currently
  500. *          the frame numbers and the used compression are printed, after all
  501. *          number of scanned/loaded frames, set FPS rate, dimensions (width/
  502. *          height/depth), sample information etc.
  503. *
  504. *       VERBOSESYNTAX -- Print information about syntax errors
  505. *
  506. *       NOVERBOSESYNTAX -- Turns the VERBOSESYNTAX option off.
  507. *
  508. *       DEBUG
  509. *       VERBOSEDEBUG -- Turns debugging mode on to get internal debugging
  510. *           info without recompiling the whole source.
  511. *
  512. *       NODEBUG
  513. *       NOVERBOSEDEBUG -- Turns the DEBUG option off.
  514. *
  515. *       IGNOREERRORS -- Ignores errors if system stream parsing fails;
  516. *           the video+audio parts attempts to load the data until the
  517. *           last scanned packet occurs.
  518. *
  519. *       NOIGNOREERRORS -- Turns the IGNOREERRORS option off.
  520. *
  521. *   NOTE
  522. *       - An invalid prefs file line will be ignored and forces the VERBOSE
  523. *         output.
  524. *
  525. *   BUGS
  526. *       - Low memory may cause that the prefs file won't be parsed.
  527. *
  528. *       - Lines are limitted to 256 chars
  529. *
  530. *       - An invalid prefs file line will be ignored.
  531. *
  532. *       - The sample path length is limitted to 200 chars. A larger
  533. *         value may crash the machine if an error occurs.
  534. *
  535. ******************************************************************************
  536. *
  537. */
  538.  
  539.  
  540. static
  541. STRPTR GetPrefsVar( struct ClassBase *cb, STRPTR name )
  542. {
  543.           STRPTR buff;
  544.     const ULONG  buffsize = 16UL;
  545.  
  546.     if( buff = (STRPTR)AllocVec( (buffsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  547.     {
  548.       if( GetVar( name, buff, buffsize, GVF_BINARY_VAR ) != (-1L) )
  549.       {
  550.         ULONG varsize = IoErr();
  551.  
  552.         varsize += 2UL;
  553.  
  554.         if( varsize > buffsize )
  555.         {
  556.           FreeVec( buff );
  557.  
  558.           if( buff = (STRPTR)AllocVec( (varsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  559.           {
  560.             if( GetVar( name, buff, varsize, GVF_BINARY_VAR ) != (-1L) )
  561.             {
  562.               return( buff );
  563.             }
  564.           }
  565.         }
  566.         else
  567.         {
  568.           return( buff );
  569.         }
  570.       }
  571.  
  572.       FreeVec( buff );
  573.     }
  574.  
  575.     return( NULL );
  576. }
  577.  
  578.  
  579. static
  580. BOOL matchstr( struct ClassBase *cb, STRPTR pat, STRPTR s )
  581. {
  582.     TEXT buff[ 512 ];
  583.  
  584.     if( pat && s )
  585.     {
  586.       if( ParsePatternNoCase( pat, buff, (sizeof( buff ) - 1) ) != (-1L) )
  587.       {
  588.         if( MatchPatternNoCase( buff, s ) )
  589.         {
  590.           return( TRUE );
  591.         }
  592.       }
  593.     }
  594.  
  595.     return( FALSE );
  596. }
  597.  
  598.  
  599. static
  600. void ReadENVPrefs( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  601. {
  602.     struct RDArgs envvarrda =
  603.     {
  604.       NULL,
  605.       256L,
  606.       0L,
  607.       0L,
  608.       NULL,
  609.       0L,
  610.       NULL,
  611.       RDAF_NOPROMPT
  612.     };
  613.  
  614.     struct
  615.     {
  616.       STRPTR  matchproject;
  617.       long   *verbose;
  618.       long   *dosyntax;
  619.       long   *nodosyntax;
  620.       long   *dodebug;
  621.       long   *nododebug;
  622.       long   *ignoreerrors;
  623.       long   *noignoreerrors;
  624.     } mpegsystemargs;
  625.  
  626.     TEXT   varbuff[ 258 ];
  627.     STRPTR var;
  628.  
  629.     if( var = GetPrefsVar( cb, "Classes/DataTypes/mpegsystem.prefs" ) )
  630.     {
  631.       STRPTR prefsline      = var,
  632.              nextprefsline;
  633.       ULONG  linecount      = 1UL;
  634.  
  635.       /* Be sure that "var" contains at least one break-char */
  636.       strcat( var, "\n" );
  637.  
  638.       while( nextprefsline = strpbrk( prefsline, "\n" ) )
  639.       {
  640.         stccpy( varbuff, prefsline, (int)MIN( (sizeof( varbuff ) - 2UL), (((ULONG)(nextprefsline - prefsline)) + 1UL) ) );
  641.  
  642.         /* be sure that this line isn't a comment line or an empty line */
  643.         if( (varbuff[ 0 ] != '#') && (varbuff[ 0 ] != ';') && (varbuff[ 0 ] != '\n') && (strlen( varbuff ) > 2UL) )
  644.         {
  645.           /* Prepare ReadArgs processing */
  646.           strcat( varbuff, "\n" );                                       /* Add NEWLINE-char            */
  647.           envvarrda . RDA_Source . CS_Buffer = varbuff;                  /* Buffer                      */
  648.           envvarrda . RDA_Source . CS_Length = strlen( varbuff ) + 1UL;  /* Set up input buffer length  */
  649.           envvarrda . RDA_Source . CS_CurChr = 0L;
  650.           envvarrda . RDA_Buffer = NULL;
  651.           envvarrda . RDA_BufSiz = 0L;
  652.           memset( (void *)(&mpegsystemargs), 0, sizeof( mpegsystemargs ) );          /* Clear result array          */
  653.  
  654.           if( ReadArgs( "MATCHPROJECT/K,"
  655.                         "VERBOSE/S,"
  656.                         "VERBOSESYNTAX/S,"
  657.                         "NOVERBOSESYNTAX/S,"
  658.                         "VERBOSEDEBUG=DEBUG/S,"
  659.                         "NOVERBOSEDEBUG=NODEBUG/S,"
  660.                         "IGNOREERRORS/S,"
  661.                         "NOIGNOREERRORS/S", (LONG *)(&mpegsystemargs), (&envvarrda) ) )
  662.           {
  663.             BOOL noignore = TRUE;
  664.  
  665.             if( (mpegsystemargs . matchproject) && (msid -> msid_ProjectName) )
  666.             {
  667.               noignore = matchstr( cb, (mpegsystemargs . matchproject), (msid -> msid_ProjectName) );
  668.             }
  669.  
  670.             if( noignore )
  671.             {
  672.               if( mpegsystemargs . verbose )
  673.               {
  674.                 OpenLogfile( cb, msid );
  675.               }
  676.  
  677.               if( mpegsystemargs . dosyntax )
  678.               {
  679.                 msid -> msid_DoSyntax = TRUE;
  680.               }
  681.  
  682.               if( mpegsystemargs . nodosyntax )
  683.               {
  684.                 msid -> msid_DoSyntax = FALSE;
  685.               }
  686.  
  687.               if( mpegsystemargs . dodebug )
  688.               {
  689.                 msid -> msid_DoDebug = TRUE;
  690.               }
  691.  
  692.               if( mpegsystemargs . nododebug )
  693.               {
  694.                 msid -> msid_DoDebug = FALSE;
  695.               }
  696.  
  697.               if( mpegsystemargs . ignoreerrors )
  698.               {
  699.                 msid -> msid_IgnoreErrors = TRUE;
  700.               }
  701.  
  702.               if( mpegsystemargs . noignoreerrors )
  703.               {
  704.                 msid -> msid_IgnoreErrors = FALSE;
  705.               }
  706.             }
  707.             else
  708.             {
  709.               verbose_printf( cb, msid, "prefs line %lu ignored\n", linecount );
  710.             }
  711.  
  712.             FreeArgs( (&envvarrda) );
  713.           }
  714.           else
  715.           {
  716.             LONG ioerr = IoErr();
  717.             TEXT errbuff[ 256 ];
  718.  
  719.             Fault( ioerr, "Classes/DataTypes/mpegsystem.prefs", errbuff, (LONG)sizeof( errbuff ) );
  720.  
  721.             error_printf( cb, msid, "preferences \"%s\" line %lu\n", errbuff, linecount );
  722.           }
  723.         }
  724.  
  725.         prefsline = ++nextprefsline;
  726.         linecount++;
  727.       }
  728.  
  729.       FreeVec( var );
  730.     }
  731. }
  732.  
  733.  
  734. static
  735. LONG LoadFrames( struct ClassBase *cb, Object *o )
  736. {
  737.     struct MPEGSystemInstData *msid  = (struct MPEGSystemInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
  738.     LONG                       error = 0L;
  739.  
  740.     InitSemaphore( (&(msid -> msid_SigSem)) );
  741.  
  742.     /* Create a memory pool for frame nodes */
  743.     if( msid -> msid_Pool = CreatePool( MEMF_PUBLIC, 8192UL, 8192UL ) )
  744.     {
  745.       BPTR  fh;               /* handle (file handle)      */
  746.       ULONG sourcetype;       /* type of stream (either DTST_FILE or DTST_RAM) */
  747.  
  748.       /* Prefs defaults */
  749.  
  750.       /* Read prefs */
  751.       ReadENVPrefs( cb, msid );
  752.  
  753.       /* Get file handle, handle type and BitMapHeader */
  754.       if( GetDTAttrs( o, DTA_SourceType,    (&sourcetype),
  755.                          DTA_Handle,        (&fh),
  756.                          DTA_Name,          (&(msid -> msid_ProjectName)),
  757.                          TAG_DONE ) == 3UL )
  758.       {
  759.         switch( sourcetype )
  760.         {
  761.           case DTST_FILE:
  762.           {
  763.               /* we have the filehandle - anything what we want... */
  764.           }
  765.               break;
  766.  
  767. #ifdef HAS_ENCODER
  768.           case DTST_RAM:
  769.           {
  770.               /* do nothing */
  771.           }
  772.               break;
  773. #endif /* HAS_ENCODER */
  774.  
  775.           default:
  776.           {
  777.               /* unsupported source type */
  778.               error = ERROR_NOT_IMPLEMENTED;
  779.           }
  780.               break;
  781.         }
  782.  
  783.         /* Any error ? */
  784.         if( error == 0L )
  785.         {
  786.           if( fh )
  787.           {
  788.             /* Run system-stream demultiplexer... */
  789.             demux( cb, msid, fh );
  790.  
  791.             /* ...success ? */
  792.             if( msid -> Handler . Process )
  793.             {
  794.               BPTR v_lock;
  795.  
  796.               /* Get first video stream */
  797.               if( v_lock = GetStreamLock( cb, msid, 0UL, FALSE ) )
  798.               {
  799.                 if( msid -> msid_CurrVideo = NewDTObject( NULL, DTA_SourceType, DTST_FILE,
  800.                                                                 DTA_Handle,     v_lock,
  801.                                                                 DTA_GroupID,    GID_ANIMATION,
  802.                                                                 TAG_DONE ) )
  803.                 {
  804.                   ULONG                 video_modeid;
  805.                   ULONG                *video_cregs;
  806.                   struct ColorRegister *video_cm;
  807.                   ULONG                 video_numcolors;
  808.                   ULONG                 video_animwidth,
  809.                                         video_animdepth,
  810.                                         video_animheight;
  811.                   ULONG                 video_frame,
  812.                                         video_numframes,
  813.                                         video_fps = 0UL,
  814.                                         video_tpf = 0UL;
  815.                   struct BitMap        *video_keyframe;
  816.  
  817.                   if( GetDTAttrs( (msid -> msid_CurrVideo),
  818.                                   ADTA_ModeID,                           (&video_modeid),
  819.                                   ADTA_CRegs,                            (&video_cregs),
  820.                                   ADTA_ColorRegisters,                   (&video_cm),
  821.                                   ADTA_NumColors,                        (&video_numcolors),
  822.                                   ADTA_Width,                            (&video_animwidth),
  823.                                   ADTA_Height,                           (&video_animheight),
  824.                                   ADTA_Depth,                            (&video_animdepth),
  825.                                   ADTA_Frame,                            (&video_frame),
  826.                                   ADTA_Frames,                           (&video_numframes),
  827.                                   XTAG( !ISV41, ADTA_FramesPerSecond ),  (&video_fps),
  828.                                   XTAG(  ISV41, ADTA_TicksPerFrame   ),  (&video_tpf),
  829.                                   ADTA_KeyFrame,                         (&video_keyframe),
  830.                                   TAG_DONE ) == 11UL )
  831.                   {
  832.                     /* This should NEVER fail, but... */
  833.                     if( video_numframes && video_keyframe && (video_fps || video_tpf) )
  834.                     {
  835.                       ULONG                *cregs;
  836.                       struct ColorRegister *cm;
  837.                       ULONG                 numcolors;
  838.  
  839.                       SetDTAttrs( o, NULL, NULL, ADTA_NumColors, video_numcolors, TAG_DONE );
  840.  
  841.                       if( GetDTAttrs( o, ADTA_CRegs,          (&cregs),
  842.                                          ADTA_ColorRegisters, (&cm),
  843.                                          ADTA_NumColors,      (&numcolors),
  844.                                          TAG_DONE ) == 3UL )
  845.                       {
  846.                         /* Check if we got memory for the palette (if we have one) */
  847.                         if( (cregs && cm && (numcolors == video_numcolors)) || (video_numcolors == 0UL) )
  848.                         {
  849.                           BPTR a_lock;
  850.  
  851.                           /* Copy base palette (if we have one) */
  852.                           if( video_numcolors )
  853.                           {
  854.                             CopyMem( video_cregs, cregs, (video_numcolors * 3UL * sizeof( ULONG )) );
  855.                             CopyMem( video_cm,    cm,    (video_numcolors * 3UL * sizeof( struct ColorRegister )) );
  856.                           }
  857.  
  858.                           msid -> msid_TicksPerFrame = ((ISV41)?(video_tpf):(TICK_FREQ / video_fps));
  859.  
  860.                           SetDTAttrs( o, NULL, NULL, DTA_ObjName,                           (msid -> msid_ProjectName),
  861.                                                      ADTA_ModeID,                           video_modeid,
  862.                                                      ADTA_Width,                            video_animwidth,
  863.                                                      ADTA_Height,                           video_animheight,
  864.                                                      ADTA_Depth,                            video_animdepth,
  865.                                                      ADTA_Frame,                            video_frame,
  866.                                                      ADTA_Frames,                           video_numframes,
  867.                                                      XTAG( !ISV41, ADTA_FramesPerSecond ),  video_fps,
  868.                                                      XTAG(  ISV41, ADTA_TicksPerFrame   ),  video_tpf,
  869.                                                      ADTA_KeyFrame,                         video_keyframe,
  870.                                                      TAG_DONE );
  871.  
  872.                           /* Get first video stream */
  873.                           if( a_lock = GetStreamLock( cb, msid, 0UL, TRUE ) )
  874.                           {
  875.                             if( msid -> msid_CurrAudio = NewDTObject( NULL, DTA_SourceType, DTST_FILE,
  876.                                                                             DTA_Handle,     a_lock,
  877.                                                                             DTA_GroupID,    GID_SOUND,
  878.                                                                             TAG_DONE ) )
  879.                             {
  880.                               ULONG volume;
  881.  
  882.                               GetDTAttrs( (msid -> msid_CurrAudio), SDTA_Sample,       (&(msid -> msid_Sample)),
  883.                                                                     SDTA_SampleLength, (&(msid -> msid_SampleLength)),
  884.                                                                     SDTA_Period,       (&(msid -> msid_Period)),
  885.                                                                     SDTA_Volume,       (&volume),
  886.                                                                     TAG_DONE );
  887.  
  888.                               msid -> msid_SamplesPerFrame = ((SysBase -> ex_EClockFrequency) * 10UL) / ((msid -> msid_Period) * (TICK_FREQ / (msid -> msid_TicksPerFrame)) * 2UL);
  889.  
  890. #if 0
  891.                               /* test test - this fixed some possible rounding errors in integer math */
  892.                               {
  893.                                 ULONG xperiod,
  894.                                       xspf;
  895.  
  896.                                 xspf    = (msid -> msid_SampleLength) / video_numframes;
  897.                                 xperiod = ((SysBase -> ex_EClockFrequency) * 10UL) / (xspf * (TICK_FREQ / (msid -> msid_TicksPerFrame)) * 2UL);
  898.  
  899.                                 if( ((xperiod * 100) / (msid -> msid_Period)) < 110 )
  900.                                 {
  901.                                   msid -> msid_SamplesPerFrame = xspf;
  902.                                   msid -> msid_Period          = xperiod;
  903.                                 }
  904.                               }
  905. #endif
  906.  
  907.                               SetDTAttrs( o, NULL, NULL, ADTA_Sample,       (msid -> msid_Sample),
  908.                                                          ADTA_SampleLength, (msid -> msid_SamplesPerFrame),
  909.                                                          ADTA_Period,       (msid -> msid_Period),
  910.                                                          ADTA_Volume,       volume,
  911.                                                          TAG_DONE );
  912.                             }
  913.                             else
  914.                             {
  915.                               /* NewDTObjectA failed */
  916.                               error = IoErr();
  917.                             }
  918.                           }
  919.                           else
  920.                           {
  921.                             /* No audio lock */
  922.                             error = IoErr();
  923.                           }
  924.                         }
  925.                         else
  926.                         {
  927.                           /* no palette memory */
  928.                           error = ERROR_NO_FREE_STORE;
  929.                         }
  930.                       }
  931.                       else
  932.                       {
  933.                         /* We did not get all attributes we need... */
  934.                         error = ERROR_OBJECT_WRONG_TYPE;
  935.                       }
  936.                     }
  937.                   }
  938.                   else
  939.                   {
  940.                     /* We did not get all attributes we need... */
  941.                     error = ERROR_OBJECT_WRONG_TYPE;
  942.                   }
  943.                 }
  944.                 else
  945.                 {
  946.                   /* NewDTObject failed */
  947.                   error = IoErr();
  948.                 }
  949.               }
  950.               else
  951.               {
  952.                 /* no video stream lock */
  953.                 error = IoErr();
  954.               }
  955.             }
  956.             else
  957.             {
  958.               /* demuxer failed */
  959.               error = msid -> Demux . retval2;
  960.             }
  961.           }
  962.           else
  963.           {
  964.             /* No file handle ? - Be sure we got a DTST_RAM sourcetype */
  965.             if( sourcetype != DTST_RAM )
  966.             {
  967.               /* No handle ! */
  968.               error = ERROR_REQUIRED_ARG_MISSING;
  969.             }
  970.           }
  971.         }
  972.       }
  973.       else
  974.       {
  975.         /* can't get required attributes from superclass */
  976.         error = ERROR_OBJECT_WRONG_TYPE;
  977.       }
  978.     }
  979.     else
  980.     {
  981.       /* no memory pool */
  982.       error = ERROR_NO_FREE_STORE;
  983.     }
  984.  
  985.     return( error );
  986. }
  987.  
  988.  
  989. /*****************************************************************************/
  990.  
  991.  
  992. static
  993. void OpenLogfile( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  994. {
  995.     if( (msid -> msid_VerboseOutput) == NULL )
  996.     {
  997.       STRPTR confile;
  998.  
  999.       if( confile = (STRPTR)AllocVec( (((msid -> msid_ProjectName)?(strlen( (msid -> msid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) )
  1000.       {
  1001.         mysprintf( cb, confile, "CON:////MPEG System DataType %s/auto/wait/close/inactive",
  1002.                    ((msid -> msid_ProjectName)?(FilePart( (msid -> msid_ProjectName) )):(NULL)) );
  1003.  
  1004.         msid -> msid_VerboseOutput = Open( confile, MODE_READWRITE );
  1005.  
  1006.         FreeVec( confile );
  1007.       }
  1008.     }
  1009. }
  1010.  
  1011.  
  1012. static
  1013. void mysprintf( struct ClassBase *cb, STRPTR buffer, STRPTR fmt, ... )
  1014. {
  1015.     APTR args;
  1016.  
  1017.     args = (APTR)((&fmt) + 1);
  1018.  
  1019.     RawDoFmt( fmt, args, (void (*))"\x16\xc0\x4e\x75", buffer );
  1020. }
  1021.  
  1022.  
  1023. static
  1024. void error_printf( struct ClassBase *cb, struct MPEGSystemInstData *msid, STRPTR format, ... )
  1025. {
  1026.     OpenLogfile( cb, msid );
  1027.  
  1028.     if( msid -> msid_VerboseOutput )
  1029.     {
  1030.       VFPrintf( (msid -> msid_VerboseOutput), format, (APTR)((&format) + 1) );
  1031.     }
  1032. }
  1033.  
  1034.  
  1035. static
  1036. void syntax_printf( struct ClassBase *cb, struct MPEGSystemInstData *msid, STRPTR format, ... )
  1037. {
  1038.     if( msid -> msid_DoSyntax )
  1039.     {
  1040.       OpenLogfile( cb, msid );
  1041.  
  1042.       if( msid -> msid_VerboseOutput )
  1043.       {
  1044.         VFPrintf( (msid -> msid_VerboseOutput), format, (APTR)((&format) + 1) );
  1045.       }
  1046.     }
  1047. }
  1048.  
  1049.  
  1050. static
  1051. void debug_printf( struct ClassBase *cb, struct MPEGSystemInstData *msid, STRPTR format, ... )
  1052. {
  1053.     if( msid -> msid_DoDebug )
  1054.     {
  1055.       OpenLogfile( cb, msid );
  1056.  
  1057.       if( msid -> msid_VerboseOutput )
  1058.       {
  1059.         VFPrintf( (msid -> msid_VerboseOutput), format, (APTR)((&format) + 1) );
  1060.       }
  1061.     }
  1062. }
  1063.  
  1064.  
  1065. static
  1066. void verbose_printf( struct ClassBase *cb, struct MPEGSystemInstData *msid, STRPTR format, ... )
  1067. {
  1068.     if( msid -> msid_VerboseOutput )
  1069.     {
  1070.       VFPrintf( (msid -> msid_VerboseOutput), format, (APTR)((&format) + 1) );
  1071.     }
  1072. }
  1073.  
  1074.  
  1075. static
  1076. ULONG SaveMPEGSystem( struct ClassBase *cb, struct IClass *cl, Object *o, struct dtWrite *dtw )
  1077. {
  1078.     ULONG retval = 0UL;
  1079.     LONG  error  /*= 0L*/;
  1080.  
  1081. #ifdef HAS_ENCODER
  1082.     /* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
  1083.     if( dtw -> dtw_FileHandle )
  1084.     {
  1085.       struct MPEGSystemInstData *msid = (struct MPEGSystemInstData *)INST_DATA( cl, o );
  1086.  
  1087.       ULONG                modeid;
  1088.       ULONG               *cregs;
  1089.       ULONG                numcolors;
  1090.       ULONG                startframe = 0UL,
  1091.                            numframes  = 0UL,
  1092.                            framestep  = 1UL;
  1093.       ULONG                fps        = 0UL;
  1094.       struct BitMap       *keyframe;
  1095.       ULONG                animwidth,
  1096.                            animheight,
  1097.                            animdepth;
  1098.  
  1099.       if( GetDTAttrs( o, ADTA_ModeID,           (&modeid),
  1100.                          ADTA_CRegs,            (&cregs),
  1101.                          ADTA_NumColors,        (&numcolors),
  1102.                          ADTA_Width,            (&animwidth),
  1103.                          ADTA_Height,           (&animheight),
  1104.                          ADTA_Depth,            (&animdepth),
  1105.                          ADTA_Frame,            (&startframe),
  1106.                          ADTA_Frames,           (&numframes),
  1107.                          ADTA_FramesPerSecond,  (&fps),
  1108.                          ADTA_KeyFrame,         (&keyframe),
  1109.                          TAG_DONE ) == 10UL )
  1110.       {
  1111.         struct TagItem     *tstate,
  1112.                            *ti;
  1113.  
  1114.         numframes -= startframe;
  1115.  
  1116.         tstate = dtw -> dtw_AttrList;
  1117.  
  1118.         while( ti = NextTagItem( (&tstate) ) )
  1119.         {
  1120.           switch( ti -> ti_Tag )
  1121.           {
  1122.             case ADTA_Frame:            startframe = ti -> ti_Data; break;
  1123.             case ADTA_Frames:           numframes  = ti -> ti_Data; break;
  1124.             case ADTA_FrameIncrement:   framestep  = ti -> ti_Data; break;
  1125.           }
  1126.         }
  1127.  
  1128.         if( framestep == 0UL ) framestep = 1UL;
  1129.  
  1130.         verbose_printf( cb, msid, "saving mpeg system movie %lu %lu %lu\n", startframe, numframes, framestep );
  1131.  
  1132.         /* here should follow the encoder part... */
  1133.       }
  1134.       else
  1135.       {
  1136.         error_printf( cb, msid, "not enougth attributes\n" );
  1137.       }
  1138.     }
  1139. #else
  1140.     error = ERROR_NOT_IMPLEMENTED; /* no encoder yet */
  1141. #endif /* HAS_ENCODER */
  1142.  
  1143.     SetIoErr( error );
  1144.  
  1145.     return( retval );
  1146. }
  1147.  
  1148. /*****************************************************************************/
  1149.  
  1150. static
  1151. UBYTE *get_buf_data( struct ClassBase *cb, struct MPEGSystemInstData *msid, long read_len )
  1152. {
  1153.     long   len_left;
  1154.     long   len_read;
  1155.     long   temp1;
  1156.     UBYTE *buf_ptr;
  1157.  
  1158.     /* Calculate how much data is left in the buffer */
  1159.     len_left = (msid -> Demux . raw_data_buf_len) - ((msid -> Demux . raw_data_buf_ptr) - (msid -> Demux . raw_data_buf));
  1160.  
  1161.     /* Not enough for the calling function's needs */
  1162.     if( len_left < read_len )
  1163.     {
  1164.       /* There is some data left, so copy to start of buffer  */
  1165.       if( len_left > 0 )
  1166.       {
  1167.         memcpy( (msid -> Demux . raw_data_buf), (msid -> Demux . raw_data_buf_ptr), (size_t)len_left );
  1168.       }
  1169.  
  1170.       msid -> Demux . raw_data_buf_ptr = &msid -> Demux . raw_data_buf[ 0 ];
  1171.  
  1172.       temp1 = MAX_DATA_BUF_LEN - len_left;  /* To fill the rest of the buffer */
  1173.  
  1174.       /* block pos */
  1175.       msid -> Demux . curr_file_pos           = Seek( (msid -> Demux . fdin), 0L, OFFSET_CURRENT ); /* Get file pos */
  1176.       msid -> Demux . curr_file_pos_in_buffer = ((msid -> Demux . raw_data_buf_ptr) + len_left);
  1177.  
  1178.       debug_printf( cb, msid, "read: %ld, len %ld, left %ld\n", (LONG)(msid -> Demux . curr_file_pos), (LONG)temp1, (LONG)len_left );
  1179.  
  1180.       len_read = Read( (msid -> Demux . fdin), (msid -> Demux . curr_file_pos_in_buffer), (LONG)temp1 );
  1181.  
  1182.       if( len_read == -1 )
  1183.       {
  1184.         LONG err = IoErr();
  1185.  
  1186.         error_printf( cb, msid, "Error: reading system file\n" );
  1187.         exitdemux( cb, msid, RETURN_FAIL, err );
  1188.       }
  1189.  
  1190.       /* no data left in file - data should never have been requested */
  1191.       if( len_read == 0 )
  1192.       {
  1193.         error_printf( cb, msid, "Error: reached EOF, requested %ld bytes\n", temp1 );
  1194.         exitdemux( cb, msid, RETURN_FAIL, DTERROR_NOT_ENOUGH_DATA );
  1195.       }
  1196.  
  1197.       msid -> Demux . raw_data_buf_len = len_left + len_read;
  1198.  
  1199.       /* Read done to end of file but still not enough data to complete request */
  1200.       if( (msid -> Demux . raw_data_buf_len) < read_len )
  1201.       {
  1202.         error_printf( cb, msid, "Error: insufficient data for read\n" );
  1203.         exitdemux( cb, msid, RETURN_FAIL, DTERROR_NOT_ENOUGH_DATA );
  1204.       }
  1205.     }
  1206.  
  1207.     buf_ptr                           = msid -> Demux . raw_data_buf_ptr; /* For return to calling function.       */
  1208.     msid -> Demux . raw_data_buf_ptr += read_len;                         /* Global advanced for use at next call. */
  1209.  
  1210.     return( buf_ptr );
  1211. }
  1212.  
  1213.  
  1214. static
  1215. UBYTE *calc_time_stamp( struct ClassBase *cb, struct MPEGSystemInstData *msid, UBYTE *buf_ptr, long *time_stamp )
  1216. {
  1217.     /* Determine Time Stamp
  1218.      * Contents:
  1219.      * Byte  0: 4 bits: depend on SCR/PTS/DTS
  1220.      *          3 bits: Time32..30,
  1221.      *          1 bit marker:1
  1222.      * Byte  1: 8 bits Time29..22.
  1223.      * Byte  2: 7 bits Time21..15,
  1224.      *          1 bit marker
  1225.      * Byte  3: 8 bits Time14..7.
  1226.      * Byte  4: 7 bits Time6..0,
  1227.      *          1 bit marker
  1228.      */
  1229.  
  1230.     *time_stamp = ((((long)(*buf_ptr)) & 0x0E) << 29);
  1231.  
  1232.     /* Marker_bit check */
  1233.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  1234.     {
  1235.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at calc_time_stamp A.\n" );
  1236.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1237.     }
  1238.  
  1239.     buf_ptr++;
  1240.  
  1241.     *time_stamp |= ((((long)(*buf_ptr)) & 0xFF) << 22);
  1242.     buf_ptr++;
  1243.  
  1244.     *time_stamp |= ((((long)(*buf_ptr)) & 0xFE) << 14);
  1245.  
  1246.     /* Marker_bit check */
  1247.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  1248.     {
  1249.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at calc_time_stamp B.\n" );
  1250.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1251.     }
  1252.  
  1253.     buf_ptr++;
  1254.  
  1255.     *time_stamp |= ((((long)(*buf_ptr)) & 0xFF) <<  7);
  1256.     buf_ptr++;
  1257.  
  1258.     *time_stamp |= ((((long)(*buf_ptr)) & 0xFE) >>  1);
  1259.  
  1260.     /* Marker_bit check */
  1261.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  1262.     {
  1263.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at calc_time_stamp C.\n" );
  1264.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1265.     }
  1266.  
  1267.     buf_ptr++;
  1268.  
  1269.     return( buf_ptr );
  1270. }
  1271.  
  1272.  
  1273. static
  1274. UBYTE get_next_start_code( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  1275. {
  1276.     UBYTE *buf_ptr = NULL; /* dead assignment, but avoids SAS/C "Warning 317: possibly uninitialized variable" */
  1277.     UWORD  zeros;
  1278.  
  1279.     /* Scan for start code; should be hex 00 00 01 for Pack Start Code,
  1280.      * System Start Code, Packet Start Code or ISO_11172_end_code.
  1281.      * Leading zeros are ignored.
  1282.      */
  1283.     for( ;; )
  1284.     {
  1285.       zeros = 0;
  1286.  
  1287.       for( ;; )
  1288.       {
  1289.         buf_ptr = get_buf_data( cb, msid, 1 );
  1290.  
  1291.         if( *buf_ptr == 0x00 )
  1292.         {
  1293.           zeros++;
  1294.         }
  1295.         else
  1296.         {
  1297.           if( zeros >= 2 )
  1298.           {
  1299.             if( *buf_ptr != 0x01 )
  1300.             {
  1301.               zeros = 0;
  1302.             }
  1303.             else
  1304.             {
  1305.               break;
  1306.             }
  1307.           }
  1308.         }
  1309.       }
  1310.  
  1311.       buf_ptr = get_buf_data( cb, msid, 1 );
  1312.  
  1313.       if( (msid -> Demux . system_found) || (*buf_ptr == 0xBB) )
  1314.       {
  1315.         break;
  1316.       }
  1317.     }
  1318.  
  1319.     switch( *buf_ptr )
  1320.     {
  1321.       case (UBYTE)0xBA:
  1322.           return( (UBYTE)PACK_START_CODE );
  1323.           break;
  1324.  
  1325.       case (UBYTE)0xB9:
  1326.           return( (UBYTE)ISO_11172_END_CODE );
  1327.           break;
  1328.  
  1329.       case (UBYTE)0xBB:
  1330.       {
  1331.           msid -> Demux . system_found = TRUE;
  1332.           verbose_printf( cb, msid, "system start\n" );
  1333.  
  1334.           return( (UBYTE)SYSTEM_START_CODE );
  1335.       }
  1336.           break;
  1337.  
  1338.       default:
  1339.          return( *buf_ptr );  /* It must be a stream_id. */
  1340.          break;
  1341.     }
  1342.  
  1343.     /* This statement should never be reached */
  1344.     return( (UBYTE)ISO_11172_END_CODE );
  1345. }
  1346.  
  1347.  
  1348. static
  1349. void read_pack_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACK_header *pki )
  1350. {
  1351.     UBYTE *buf_ptr;
  1352.  
  1353.     pki -> SCR = 0;
  1354.  
  1355.     buf_ptr = get_buf_data( cb, msid, PACK_HEADER_LENGTH );
  1356.  
  1357.     /* Determine System Clock Reference (SCR)
  1358.      * Check marker_bits: '0010' = 0x2
  1359.      */
  1360.  
  1361.     if( (*buf_ptr & (UBYTE)0xF0) != (UBYTE)0x20 )
  1362.     {
  1363.       syntax_printf( cb, msid, "Expecting '0010' after pack_start_code.\n" );
  1364.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1365.     }
  1366.  
  1367.     buf_ptr = calc_time_stamp( cb, msid, buf_ptr, (&(pki -> SCR)) );
  1368.  
  1369.     /* Determine Mux Rate
  1370.      * Contents:
  1371.      * Byte 5: 1 bit marker,
  1372.      *         7 bits mux_rate.
  1373.      * Byte 6: 8 bits mux_rate.
  1374.      * Byte 7: 7 bits mux_rate,
  1375.      *         1 bit marker
  1376.      */
  1377.     pki -> mux_rate = ((((long)(*buf_ptr)) & 0x7F) << 14);
  1378.  
  1379.     /* Marker_bit check */
  1380.     if( (*buf_ptr & (UBYTE)0x80) != (UBYTE)0x80 )
  1381.     {
  1382.       syntax_printf( cb, msid, "byte= %lx.\n", *buf_ptr );
  1383.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at read_pack_header A.\n" );
  1384.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1385.     }
  1386.  
  1387.     buf_ptr++;
  1388.  
  1389.     pki -> mux_rate |= ((((long)(*buf_ptr)) & 0xFF) << 7);
  1390.     buf_ptr++;
  1391.  
  1392.     pki -> mux_rate |= ((((long)(*buf_ptr)) & 0xFE) >> 1);
  1393.  
  1394.     /* Marker_bit check */
  1395.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  1396.     {
  1397.       syntax_printf( cb, msid, "Expecting marker_bit value '1' at read_pack_header B.\n" );
  1398.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1399.     }
  1400. }
  1401.  
  1402.  
  1403. static
  1404. void read_system_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, SYSTEM_header *si )
  1405. {
  1406.     UBYTE *buf_ptr;
  1407.     long   j;
  1408.     UBYTE  test;
  1409.  
  1410.     /* Read System Header Length: 2 Bytes after start code.
  1411.      * Length of header after header length bytes.
  1412.      * Bytes  0 & 1: 8 bits header_length--high & low
  1413.      */
  1414.     buf_ptr = get_buf_data( cb, msid, 2 );
  1415.     si -> header_length  = (ULONG)(((long)(*buf_ptr)) << 8);
  1416.     buf_ptr++;
  1417.     si -> header_length |= (ULONG)(((long)(*buf_ptr)) & 0xFF);
  1418.  
  1419.     /* Read the rest of the header */
  1420.     buf_ptr = get_buf_data( cb, msid, (si -> header_length) );
  1421.  
  1422.     /* Byte  0: 1 bit marker, 
  1423.      *          7 bits rate_bound--high
  1424.      */
  1425.     si -> rate_bound  = (ULONG)((((long)*buf_ptr) & 0x7F) << 15);
  1426.  
  1427.     /* Marker bit check */
  1428.     if( (*buf_ptr & (UBYTE)0x80) != (UBYTE)0x80 )
  1429.     {
  1430.       syntax_printf( cb, msid, "Expecting marker_bit value '1' before rate_bound--high.\n" );
  1431.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1432.     }
  1433.  
  1434.     buf_ptr++;
  1435.  
  1436.     /* Byte  1: 8 bits rate_bound--mid */
  1437.     si -> rate_bound += (ULONG)((((long)*buf_ptr) & 0xFF) << 7);
  1438.     buf_ptr++;
  1439.  
  1440.     /* Byte  2: 7 bits rate_bound-low,
  1441.      *          1 bit marker
  1442.      */
  1443.     si -> rate_bound += (ULONG)((((long)*buf_ptr) & 0xFE) >>  1);
  1444.  
  1445.     /* Marker bit check */
  1446.     if( (*buf_ptr & (UBYTE)0x01) != (UBYTE)0x01 )
  1447.     {
  1448.       syntax_printf( cb, msid, "Expecting marker_bit value '1' after rate_bound.\n" );
  1449.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1450.     }
  1451.  
  1452.     buf_ptr++;
  1453.  
  1454.     /* Byte  3: 6 bits audio_bound, 
  1455.      * 1 bit fixed_flag,
  1456.      * 1bit CSPS_flag 
  1457.      */
  1458.     si -> audio_bound = (ULONG)((((long)*buf_ptr) & 0xFF) >> 2);
  1459.     si -> fixed_flag  =  (BOOL)((((long)*buf_ptr) & 0x02) >> 1);
  1460.     si -> CSPS_flag   =  (BOOL) (((long)*buf_ptr) & 0x01);
  1461.     buf_ptr++;
  1462.  
  1463.     /* Byte 4: 1b system_audio_lock_flag,
  1464.      *         1b system_video_lock_flag,
  1465.      *         1b marker,
  1466.      *         5b video_bound
  1467.      */
  1468.     si -> system_audio_lock_flag =  (BOOL)((((long)*buf_ptr) & 0x80) >> 7);
  1469.     si -> system_video_lock_flag =  (BOOL)((((long)*buf_ptr) & 0x40) >> 6);
  1470.     si -> video_bound            = (ULONG) (((long)*buf_ptr) & 0x1F);
  1471.  
  1472.     /* Marker bit check */
  1473.     if( (*buf_ptr & (UBYTE)0x20) != (UBYTE)0x20 )
  1474.     {
  1475.       syntax_printf( cb, msid, "Expecting marker_bit value '1' after system_video_lock_flag.\n" );
  1476.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1477.     }
  1478.  
  1479.     buf_ptr++;
  1480.  
  1481.     if( *buf_ptr != (UBYTE)0xFF )
  1482.     {
  1483.       syntax_printf( cb, msid, "Reserved byte not set to default\n" );
  1484.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1485.     }
  1486.  
  1487.     buf_ptr++;
  1488.  
  1489.     if( (si -> header_length) == 6 )
  1490.     {
  1491.       return;
  1492.     }
  1493.  
  1494.     j = 0;
  1495.  
  1496.     while( (ULONG)buf_ptr < (ULONG)(msid -> Demux . raw_data_buf_ptr) )
  1497.     {
  1498.       /* All lmntry stream_id's ... */
  1499.       test = (*buf_ptr & (UBYTE)0x80);
  1500.  
  1501.       if( test == 0 )
  1502.       {
  1503.         error_printf( cb, msid, "system header length incorrect\n" );
  1504.         exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1505.       }
  1506.  
  1507.       si -> STD_buffer_info[ j ] . stream_id = (*buf_ptr & (UBYTE)0xFF);
  1508.  
  1509.       buf_ptr++;
  1510.  
  1511.       /* Check marker_bits */
  1512.       if( (*buf_ptr & (UBYTE)0xC0) != (UBYTE)0xC0 )
  1513.       {
  1514.         syntax_printf( cb, msid, "Expecting placeholder bit values '11' after stream_id.\n" );
  1515.         exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1516.       }
  1517.  
  1518.       si -> STD_buffer_info[ j ] . STD_buffer_bound_scale = (*buf_ptr & (UBYTE)0x20) >> 5;
  1519.       si -> STD_buffer_info[ j ] . STD_buffer_size_bound  = (*buf_ptr & (UBYTE)0x1F) << 8;
  1520.  
  1521.       buf_ptr++;
  1522.  
  1523.       si -> STD_buffer_info[ j ] . STD_buffer_size_bound  |= *buf_ptr & (UBYTE)0xFF;
  1524.  
  1525.       buf_ptr++;
  1526.  
  1527.       j++;
  1528.     }
  1529. }
  1530.  
  1531.  
  1532. static
  1533. void read_packet_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACKET_header *pi )
  1534. {
  1535.     UBYTE *buf_ptr;
  1536.     UBYTE  test,
  1537.            test1;
  1538.     long   i;
  1539.  
  1540.     pi -> PTS = 0;
  1541.     pi -> DTS = 0;
  1542.  
  1543.     /* read packet length */
  1544.     buf_ptr = get_buf_data( cb, msid, 2 );
  1545.  
  1546.     /* Bytes 0 & 1: 8 bits packet_length -- high & low */
  1547.     pi -> packetlength  = (ULONG)(((long)*buf_ptr) << 8);
  1548.     buf_ptr++;
  1549.     pi -> packetlength |= (ULONG)(((long)*buf_ptr) & 0xFF);
  1550.  
  1551.     /* Get the remainder of the packet. */
  1552.     buf_ptr = get_buf_data( cb, msid, (pi -> packetlength) );
  1553.  
  1554.     /* private stream 2 */
  1555.     if( (pi -> stream_id) <= (UBYTE)0xBF )
  1556.     {
  1557.       pi -> packet_ptr = buf_ptr;
  1558.       return;
  1559.     }
  1560.  
  1561.     /* Skip over any stuffing Bytes 1111 1111 (16 max)
  1562.      * Count to 17 to see if there are more than allowed in the spec.
  1563.      */
  1564.  
  1565.     i = 0;
  1566.  
  1567.     while( (*buf_ptr == (UBYTE)0xFF) && (i < 17) )
  1568.     {
  1569.       buf_ptr++;
  1570.       pi -> packetlength--;
  1571.       i++;
  1572.     }
  1573.  
  1574.     if( i == 17 )
  1575.     {
  1576.       error_printf( cb, msid, "Too many stuffing bytes after packet_length\n" );
  1577.       exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1578.     }
  1579.  
  1580.     /* If nextbits =='01' read STD_buffer_scale & _size
  1581.      * Byte: 2b '01', 
  1582.      *       1b STD_buffer_scale,
  1583.      *       5b STD_buffer_size-hi
  1584.      * Byte: 8 bits STD_buffer_size--lo
  1585.      */
  1586.     test1 = *buf_ptr & (UBYTE)0xC0;
  1587.  
  1588.     if( test1 == (UBYTE)0x40 )
  1589.     {
  1590.      /* read STD values */
  1591.       pi -> STD_buffer_scale = (*buf_ptr & (UBYTE)0x20) >> 5;
  1592.       pi -> STD_buffer_size  = (*buf_ptr & (UBYTE)0x1F) << 8;
  1593.       buf_ptr++;
  1594.  
  1595.       pi -> packetlength--;
  1596.       pi -> STD_buffer_size |= (*buf_ptr & (UBYTE)0xFF);
  1597.       buf_ptr++;
  1598.  
  1599.       pi -> packetlength--;
  1600.     }
  1601.  
  1602.     /* Determine whether to read in PTS, PTS & DTS, or neither before data. */
  1603.     test = (*buf_ptr & (UBYTE)0xF0);
  1604.  
  1605.     switch( test )
  1606.     {
  1607.       case (UBYTE)0x20:   /* Get PTS only */
  1608.       {
  1609.           buf_ptr = calc_time_stamp( cb, msid, buf_ptr, (&(pi -> PTS)) );
  1610.           pi -> packetlength -= 5;
  1611.       }
  1612.           break;
  1613.  
  1614.       case (UBYTE)0x30:   /* Get PTS & DTS. Both same format as PTS above.
  1615.                            * pts and data
  1616.                            */
  1617.       {
  1618.           buf_ptr = calc_time_stamp( cb, msid, buf_ptr, (&(pi -> PTS)) );
  1619.  
  1620.           /* Get DTS */
  1621.           if( (*buf_ptr & (UBYTE)0xF0) != (UBYTE)0x10 )
  1622.           {
  1623.             syntax_printf( cb, msid, "Expecting bits '0001' before DTS in read_packet_header\n" );
  1624.             exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1625.           }
  1626.  
  1627.           buf_ptr = calc_time_stamp( cb, msid, buf_ptr, (&(pi -> DTS)) );
  1628.           pi -> packetlength -= 10;
  1629.       }
  1630.           break;
  1631.  
  1632.       case (UBYTE)0x00:
  1633.       {
  1634.           if( *buf_ptr != (UBYTE)0x0F )
  1635.           {
  1636.             error_printf( cb, msid, "not a valid packet time sequence\n" );
  1637.             exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1638.           }
  1639.  
  1640.           buf_ptr++;
  1641.           pi -> packetlength--;
  1642.       }
  1643.           break;
  1644.  
  1645.       default:
  1646.       {
  1647.           error_printf( cb, msid, "invalid time code in packet\n" );
  1648.           exitdemux( cb, msid, RETURN_FAIL, DTERROR_INVALID_DATA );
  1649.       }
  1650.           break;
  1651.     }
  1652.  
  1653.     /* packetlength should have been properly set by the above */
  1654.  
  1655.     pi -> packet_ptr = buf_ptr;
  1656. }
  1657.  
  1658.  
  1659. static
  1660. void print_pack_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACK_header *pki )
  1661. {
  1662.     long mux_byte_rate = (pki -> mux_rate) * 50;
  1663.  
  1664.     verbose_printf( cb, msid, "PACK HEADER: SCR = %ld, Mux Rate = %ld, or %ld Bytes per second\n",
  1665.                     (LONG)(pki -> SCR), (LONG)(pki -> mux_rate), mux_byte_rate );
  1666. }
  1667.  
  1668.  
  1669. static
  1670. void print_system_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, SYSTEM_header *si )
  1671. {
  1672.     long  i            = 0;
  1673.     long  stream_num   = 0;
  1674.     long  buf_byte_size_bound;
  1675.     UBYTE stream_type  = 0;
  1676.  
  1677.     verbose_printf( cb, msid, "SYSTEM HEADER: Hdr Len = %ld, Rate bound = %ld, Audio bound = %ld,\n",
  1678.                     (LONG)(si -> header_length),
  1679.                     (LONG)(si -> rate_bound),
  1680.                     (LONG)(si -> audio_bound) );
  1681.  
  1682.     verbose_printf( cb, msid, "Fixed flag = %ld, CSPS flag = %ld, Sys audio lock flag = %ld,\n",
  1683.              (LONG)(si -> fixed_flag),
  1684.              (LONG)(si -> CSPS_flag),
  1685.              (LONG)(si -> system_audio_lock_flag) );
  1686.  
  1687.     verbose_printf( cb, msid, "Sys video lock flag = %ld, Video bound = %ld\n",
  1688.             (LONG)(si -> system_video_lock_flag), (LONG)(si -> video_bound) );
  1689.  
  1690.     while( si -> STD_buffer_info[ i ] . stream_id != 0 )
  1691.     {
  1692.       if( ((si -> STD_buffer_info[ i ] . stream_id >> 5) & 0x6) == 0x6 )
  1693.       {
  1694.         stream_type = 'A';
  1695.         stream_num  = (long)((si -> STD_buffer_info[ i ] . stream_id) & 0x1F);
  1696.       }
  1697.  
  1698.       if( ((si -> STD_buffer_info[ i ] . stream_id >> 4) & 0xE) == 0xE )
  1699.       {
  1700.         stream_type = 'V';
  1701.         stream_num  = (long)((si -> STD_buffer_info[ i]  . stream_id) & 0x0F);
  1702.       }
  1703.  
  1704.       if( si -> STD_buffer_info[ i ] . STD_buffer_bound_scale == 0 )
  1705.       {
  1706.         buf_byte_size_bound = si -> STD_buffer_info[ i ] . STD_buffer_size_bound * 128;
  1707.       }
  1708.       else
  1709.       {
  1710.         buf_byte_size_bound= si -> STD_buffer_info[ i ] . STD_buffer_size_bound * 1024;
  1711.       }
  1712.  
  1713.       verbose_printf( cb, msid, "STD buf %ld: Stream %lc%ld, Buf bound scale %ld, Buf size bound %ld or %ld bytes\n",
  1714.               i, stream_type, stream_num,
  1715.               (si -> STD_buffer_info[ i ] . STD_buffer_bound_scale),
  1716.               (si -> STD_buffer_info[ i ] . STD_buffer_size_bound),
  1717.               buf_byte_size_bound );
  1718.       i++;
  1719.     }
  1720. }
  1721.  
  1722.  
  1723. static
  1724. void print_packet_header( struct ClassBase *cb, struct MPEGSystemInstData *msid, PACKET_header *pi )
  1725. {
  1726.     long   stream_num  = 0;
  1727.     UBYTE  stream_type = 0;
  1728.  
  1729.     if( ((pi -> stream_id >> 5) & 0x6) == 0x6 )
  1730.     {
  1731.       stream_type = 'A';
  1732.       stream_num = (long)((pi -> stream_id) & 0x1F);
  1733.     }
  1734.  
  1735.     if( ((pi -> stream_id >> 4) & 0xE) == 0xE )
  1736.     {
  1737.       stream_type = 'V';
  1738.       stream_num = (long)((pi -> stream_id) & 0x0F);
  1739.     }
  1740.  
  1741.     verbose_printf( cb, msid, "PACKET HDR %lc%ld: %ldB, STD buf scale %ld, ..size %ld, PTS %ld, DTS %ld\n",
  1742.             stream_type,
  1743.             stream_num,
  1744.             (pi -> packetlength),
  1745.             (pi -> STD_buffer_scale),
  1746.             (pi -> STD_buffer_size),
  1747.             (pi -> PTS),
  1748.             (pi -> DTS) );
  1749. }
  1750.  
  1751.  
  1752. static
  1753. void demux( struct ClassBase *cb, struct MPEGSystemInstData *msid, BPTR file )
  1754. {
  1755.     PACK_header    pack_info;
  1756.     PACK_header   *pack_info_p = &pack_info;
  1757.     SYSTEM_header  sys_info;
  1758.     SYSTEM_header *sys_info_p  = &sys_info;
  1759.     PACKET_header  pkt_info;
  1760.     PACKET_header *pkt_info_p  = &pkt_info;
  1761.  
  1762.     long           i,
  1763.                    j;
  1764.     long           current_audio = 0;
  1765.     long           current_video = 0;
  1766.     long           demux_id[ MAX_MPEG_STREAMS ];
  1767.     UBYTE          next_code;
  1768.  
  1769.     /* Alloc input buffer */
  1770.     if( msid -> Demux . raw_data_buf = (UBYTE *)AllocVec( MAX_DATA_BUF_LEN, MEMF_PUBLIC ) )
  1771.     {
  1772.       /* Set "point of return" on decoder exit/error */
  1773.       if( setjmp( (msid -> Demux . exit_buf) ) == 0 )
  1774.       {
  1775.         /* Init remaining fields */
  1776.         msid -> Demux . raw_data_buf_len = 0;
  1777.         msid -> Demux . raw_data_buf_ptr = msid -> Demux . raw_data_buf;
  1778.  
  1779.         msid -> Demux . fdin = file;
  1780.  
  1781.         /* Read and write data. */
  1782.         for( ;; )
  1783.         {
  1784.           next_code = get_next_start_code( cb, msid );
  1785.  
  1786.           verbose_printf( cb, msid, "next_code = %lx\n", (LONG)next_code );
  1787.  
  1788.           /* next_code identifies whether the stream is at
  1789.            *  the beginning of a system stream, a pack, or a packet,
  1790.            *  or if it is at the end of a system stream.
  1791.            */
  1792.           switch( next_code )
  1793.           {
  1794.             case ((UBYTE)PACK_START_CODE):      /* 0xBA */
  1795.             {
  1796.                 read_pack_header( cb, msid, pack_info_p );
  1797.                 print_pack_header( cb, msid, pack_info_p );
  1798.             }
  1799.                 break;
  1800.  
  1801.             case ((UBYTE)SYSTEM_START_CODE):      /* 0xBB */
  1802.             {
  1803.                 read_system_header( cb, msid, sys_info_p );
  1804.                 print_system_header( cb, msid, sys_info_p );
  1805.  
  1806.                 msid -> Demux . N = sys_info_p -> audio_bound;
  1807.                 msid -> Demux . M = sys_info_p -> video_bound;
  1808.  
  1809.                 verbose_printf( cb, msid, " %ld audio, %ld video\n", (msid -> Demux . N), (msid -> Demux . M) );
  1810.  
  1811.                 current_audio = 0;
  1812.                 current_video = msid -> Demux . N;
  1813.  
  1814.                 for( i = 0 ; i < MAX_MPEG_STREAMS ; i++ )
  1815.                 {
  1816.                   demux_id[ i ] = -1;
  1817.                 }
  1818.             }
  1819.                 break;
  1820.  
  1821.             case ((UBYTE)ISO_11172_END_CODE):      /* 0xB9 */
  1822.             {
  1823.                 verbose_printf( cb, msid, "end of system stream reached\n" );
  1824.  
  1825.                 exitdemux( cb, msid, RETURN_OK, 0L );
  1826.             }
  1827.                 break;
  1828.  
  1829.             default:   /* PACKET START CODE & stream_id */
  1830.             {
  1831.                 pkt_info_p -> stream_id = next_code;
  1832.                 read_packet_header( cb, msid, pkt_info_p );
  1833.                 print_packet_header( cb, msid, pkt_info_p );
  1834.  
  1835.                 /* The stream_id identifies the stream by type and number */
  1836.                 switch( pkt_info_p -> stream_id )
  1837.                 {
  1838.                   case( (UBYTE)0xB8 ): /* may need more work */
  1839.                   {
  1840.                       /* Following STD_buffer_scale and _size refer to
  1841.                        * all audio streams in the muxed stream
  1842.                        */
  1843.                       error_printf( cb, msid, "Error handling common audio STD_buffer_scale and _size.\n" );
  1844.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1845.                   }
  1846.                       break;
  1847.  
  1848.                   case( (UBYTE)0xB9 ): /* may need more work */
  1849.                   {
  1850.                       /* Following STD_buffer_scale and _size refer to
  1851.                        * all video streams in the muxed stream
  1852.                        */
  1853.                       error_printf( cb, msid, "Error handling common video STD_buffer_scale and _size.\n" );
  1854.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1855.                   }
  1856.                       break;
  1857.  
  1858.                   case( (UBYTE)0xBC ):
  1859.                   {
  1860.                       /* Reserved stream: discard */
  1861.                       error_printf( cb, msid, "Received reserved stream\n" );
  1862.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1863.                   }
  1864.                       break;
  1865.  
  1866.                   case( (UBYTE)0xBD ):
  1867.                   {
  1868.                       /* private_stream_1: discard */
  1869.                       error_printf( cb, msid, "Received private_stream_1\n" );
  1870.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1871.                   }
  1872.                       break;
  1873.  
  1874.                   case( (UBYTE)0xBE ):  /* data bytes all FF */
  1875.                   {
  1876.                       /* Padding stream: discard */
  1877.                       verbose_printf( cb, msid, "Received padding stream\n" );
  1878.                   }
  1879.                       break;
  1880.  
  1881.                   case( (UBYTE)0xBF ):
  1882.                   {
  1883.                       /* private_stream_2: discard */
  1884.                       error_printf( cb, msid, "Received private_stream_2\n" );
  1885.  
  1886.                       exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1887.                   }
  1888.                       break;
  1889.  
  1890.                   default:
  1891.                   {
  1892.                       /* The stream is an audio, video, or reserved_data stream.
  1893.                        * Convert stream_id to C0 to 0, EF to 48
  1894.                        */
  1895.                       i = (((long)pkt_info_p -> stream_id) & 0xFF) - 192;
  1896.  
  1897.                       if( i < 0 )
  1898.                       {
  1899.                         /* Invalid stream: do nothing */
  1900.                       }
  1901.                       else
  1902.                       {
  1903.                         /* Audio or Video stream. */
  1904.                         if( i < 48 )
  1905.                         {
  1906.                           BOOL                isaudio = (i < 32);
  1907.                           struct PacketBlock *pb;
  1908.  
  1909.                           if( demux_id[ i ] == -1 )
  1910.                           {
  1911.                             /* A new stream */
  1912.                             if( isaudio )
  1913.                             {
  1914.                               /* Audio */
  1915.                               demux_id[ i ] = current_audio;
  1916.                               current_audio++;
  1917.                             }
  1918.                             else
  1919.                             {
  1920.                               demux_id[ i ] = current_video;
  1921.                               current_video++;
  1922.                             }
  1923.                           }
  1924.  
  1925.                           j = demux_id[ i ];
  1926.  
  1927.                           /* No file ? - Then create it ! */
  1928.                           if( (msid -> Demux . fd_demuxa[ j ] . sl_handle) == NULL )
  1929.                           {
  1930.                             NewList( (struct List *)(&(msid -> Demux . fd_demuxa[ j ] . sl_packetblocklist)) );
  1931.  
  1932.                             msid -> Demux . fd_demuxa[ j ] . sl_handle = msid -> Demux . fdin;
  1933.                           }
  1934.  
  1935.                           /* block pos */
  1936.                           verbose_printf( cb, msid, "write: off %ld len %ld\n", (msid -> Demux . curr_file_pos +  /* file pos */
  1937.                                           (long)((pkt_info_p -> packet_ptr) - msid -> Demux . curr_file_pos_in_buffer)),
  1938.                                           (pkt_info_p -> packetlength) );
  1939.  
  1940.                           /* Create, fill and queue a PacketBlock node */
  1941.                           pb = (struct PacketBlock *)AllocPooled( (msid -> msid_Pool), (ULONG)sizeof( struct PacketBlock ) );
  1942.                           if( pb == NULL ) exitdemux( cb, msid, RETURN_FAIL, ERROR_NO_FREE_STORE );
  1943.  
  1944.                           pb -> system_offset = (msid -> Demux . curr_file_pos + (long)((pkt_info_p -> packet_ptr) - msid -> Demux . curr_file_pos_in_buffer)); /* file pos */
  1945.                           pb -> length        = (pkt_info_p -> packetlength);
  1946.  
  1947.                           /* Inc stream size */
  1948.                           msid -> Demux . fd_demuxa[ j ] . sl_size += pb -> length;
  1949.  
  1950.                           AddTail( (struct List *)(&(msid -> Demux . fd_demuxa[ j ] . sl_packetblocklist)), (struct Node *)(&(pb -> node)) );
  1951.                         }
  1952.                         else
  1953.                         {
  1954.                           if( i >= 48 )
  1955.                           {
  1956.                             /* It's a reserved data stream.
  1957.                              * Additional functionality will be implementation dependent
  1958.                              */
  1959.                             verbose_printf( cb, msid, "Reserved data stream %ld is being ignored.\n", i );
  1960.                             break;
  1961.                           }
  1962.                           else
  1963.                           {
  1964.                             /* Should never be reached. */
  1965.                             error_printf( cb, msid, "Unrecognized stream ID: %ld %lx %lc\n",
  1966.                                           (pkt_info_p -> stream_id),
  1967.                                           (pkt_info_p -> stream_id),
  1968.                                           (long)(pkt_info_p -> stream_id) );
  1969.  
  1970.                             exitdemux( cb, msid, RETURN_FAIL, DTERROR_UNKNOWN_COMPRESSION );
  1971.                           }
  1972.                         }
  1973.                       }
  1974.                   }
  1975.                       break;
  1976.  
  1977.               }
  1978.             }
  1979.           }
  1980.         }
  1981.       }
  1982.  
  1983.       /* Success ? */
  1984.       if( ((msid -> Demux . retval) <= RETURN_WARN) || (msid -> msid_IgnoreErrors) )
  1985.       {
  1986.         RunHandler( cb, msid );
  1987.       }
  1988.  
  1989.       FreeVec( (msid -> Demux . raw_data_buf) );
  1990.     }
  1991. }
  1992.  
  1993.  
  1994. static
  1995. void exitdemux( struct ClassBase *cb, struct MPEGSystemInstData *msid, LONG result, LONG result2 )
  1996. {
  1997.     msid -> Demux . retval  = result;
  1998.     msid -> Demux . retval2 = result2;
  1999.  
  2000.     longjmp( (msid -> Demux . exit_buf), 1 );
  2001. }
  2002.  
  2003.  
  2004. /*****************************************************************************/
  2005.  
  2006. static
  2007. BPTR GetStreamLock( struct ClassBase *cb, struct MPEGSystemInstData *msid, ULONG num, BOOL isaudio )
  2008. {
  2009.       if( msid -> Handler . Process )
  2010.       {
  2011.         BPTR lock;
  2012.  
  2013.         num += (isaudio)?(0UL):(msid -> Demux . N); /* Add video ID-offset if neccesary */
  2014.  
  2015.         lock = (BPTR)DoPkt( (&(msid -> Handler . Process -> pr_MsgPort)), ACTION_COPY_DIR, MKBADDR( (num * 16) ), 0L, 0L, 0L, 0L );
  2016.  
  2017.         return( lock );
  2018.       }
  2019.  
  2020.       return( NULL );
  2021. }
  2022.  
  2023.  
  2024. static
  2025. void RunHandler( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  2026. {
  2027.     if( msid -> Handler . Process = CreateNewProcTags( NP_Entry,        Handler,
  2028.                                                        NP_Name,         "MPEG System Demux",
  2029.                                                        NP_Priority,     9L,
  2030.                                                        NP_StackSize,    16384UL,
  2031.                                                        TAG_DONE ) )
  2032.     {
  2033.       /* Initialize the message */
  2034.       msid -> Handler . Startup . sm_Message . mn_Node . ln_Type = NT_MESSAGE;
  2035.       msid -> Handler . Startup . sm_Message . mn_Length         = sizeof( struct StartupMsg );
  2036.       msid -> Handler . Startup . sm_CB                          = cb;
  2037.       msid -> Handler . Startup . sm_msid                        = msid;
  2038.  
  2039.       /* Send the information to the process */
  2040.       PutMsg( (&(msid -> Handler . Process -> pr_MsgPort)), (&(msid -> Handler . Startup . sm_Message)) );
  2041.     }
  2042. }
  2043.  
  2044.  
  2045. /* Kill our virtual demux filesystem and wait until it is really dead...
  2046.  * (Should be replaced by a version which uses exec.library/Wait)
  2047.  */
  2048. static
  2049. void KillHandler( struct ClassBase *cb, struct MPEGSystemInstData *msid )
  2050. {
  2051.     while( (msid -> Handler . Process) )
  2052.     {
  2053.       Forbid();
  2054.  
  2055.         if( msid -> Handler . Process )
  2056.         {
  2057.           Signal( (&(msid -> Handler . Process -> pr_Task)), SIGBREAKF_CTRL_C );
  2058.         }
  2059.  
  2060.       Permit();
  2061.  
  2062.       /* Wait a 1/25 sec before trying it again... */
  2063.       Delay( (TICKS_PER_SECOND / 25UL) );
  2064.     }
  2065. }
  2066.  
  2067.  
  2068. /* virtual demux filesystem handler entry */
  2069. DISPATCHERFLAGS
  2070. static
  2071. void Handler( void )
  2072. {
  2073. #ifdef SysBase
  2074. #undef SysBase
  2075. #endif
  2076.     struct ExecBase           *SysBase = (*((struct ExecBase **)4UL));
  2077.     struct Process            *pr;
  2078.     struct StartupMsg         *sm;
  2079.     struct ClassBase          *cb;
  2080.     struct MPEGSystemInstData *msid;
  2081.     ULONG                      sigflags;
  2082.     struct Message            *msg;
  2083.     BOOL                       done = FALSE;
  2084.  
  2085.     /* Find out who we are */
  2086.     pr = (struct Process *)FindTask( NULL );
  2087.  
  2088.     /* Get the startup message */
  2089.     WaitPort( (&(pr -> pr_MsgPort)) );
  2090.     sm = (struct StartupMsg *)GetMsg( (&(pr -> pr_MsgPort)) );
  2091.  
  2092.     /* Pull all the information required from the startup message */
  2093.     cb   = sm -> sm_CB;
  2094.     msid = sm -> sm_msid;
  2095.  
  2096.     do
  2097.     {
  2098.       sigflags = Wait( (1UL << (pr -> pr_MsgPort . mp_SigBit)) | SIGBREAKF_CTRL_C );
  2099.  
  2100.       if( sigflags & SIGBREAKF_CTRL_C )
  2101.       {
  2102.         done = TRUE;
  2103.       }
  2104.  
  2105.       while( msg = GetMsg( (&(pr -> pr_MsgPort)) ) )
  2106.       {
  2107.         dispatch_packet( cb, msid, (struct DosPacket *)(msg -> mn_Node . ln_Name) );
  2108.       }
  2109.     } while( (!done) || (msid -> Handler . OpenCount) );
  2110.  
  2111.     Forbid();
  2112.  
  2113.       msid -> Handler . Process = NULL;
  2114. #define SysBase (cb -> cb_SysBase)
  2115. }
  2116.  
  2117.  
  2118. static
  2119. void dispatch_packet( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct DosPacket *dp )
  2120. {
  2121.     struct MsgPort      *rport;
  2122.     struct StreamHandle *sh;
  2123.  
  2124.     switch( dp -> dp_Type )
  2125.     {
  2126.       case ACTION_FINDINPUT:
  2127.       case ACTION_FH_FROM_LOCK:
  2128.       {
  2129.           struct FileHandle  *fh             = (struct FileHandle  *)BADDR( (dp -> dp_Arg1) );
  2130.           struct FileLock    *fl             = (struct FileLock    *)BADDR( (dp -> dp_Arg2) );
  2131.           LONG                stream_index   = fl -> fl_Key;
  2132.  
  2133.           if( sh = (struct StreamHandle *)AllocVec( sizeof( struct StreamHandle ), MEMF_PUBLIC ) )
  2134.           {
  2135.             /* init StreamHandle */
  2136.             sh -> sl      = (&(msid -> Demux . fd_demuxa[ stream_index ]));
  2137.             sh -> currpos = 0L;
  2138.  
  2139.             /* Init FileHandle */
  2140.             fh -> fh_Port     = (struct MsgPort *)DOSFALSE;                   /* non-interactive handler    */
  2141.             fh -> fh_Arg1     = (LONG)sh;                                     /* set to struct StreamHandle */
  2142.             fh -> fh_Type     = (&(msid -> Handler . Process -> pr_MsgPort));
  2143.  
  2144.             /* Handler in-use */
  2145.             msid -> Handler . OpenCount++;
  2146.  
  2147.             if( (dp -> dp_Type) == ACTION_FH_FROM_LOCK )
  2148.             {
  2149.               /* Here we can "eat" the given filelock... */
  2150.               FreeLock( cb, msid, fl );
  2151.             }
  2152.  
  2153.             dp -> dp_Res1 = DOSTRUE;  /* success */
  2154.             dp -> dp_Res2 = 0L;       /* No error */
  2155.           }
  2156.           else
  2157.           {
  2158.             dp -> dp_Res1 = DOSFALSE; /* failure */
  2159.             dp -> dp_Res2 = IoErr();  /* Cause ? */
  2160.           }
  2161.       }
  2162.           break;
  2163.  
  2164.       case ACTION_END:
  2165.       {
  2166.           sh = (struct StreamHandle *)(dp -> dp_Arg1);
  2167.  
  2168.           if( sh )
  2169.           {
  2170.             FreeVec( sh );
  2171.           }
  2172.  
  2173.           msid -> Handler . OpenCount--;
  2174.  
  2175.           dp -> dp_Res1 = DOSTRUE;
  2176.           dp -> dp_Res2 = 0L;
  2177.       }
  2178.           break;
  2179.  
  2180.       case ACTION_READ:
  2181.       {
  2182.           LONG   stream_offset  = 0L;
  2183.           LONG   read_size      = (dp -> dp_Arg3);
  2184.           UBYTE *dest           = (UBYTE *)(dp -> dp_Arg2);
  2185.           LONG   error          = 0L;
  2186.           LONG   curr_read_size = 0L; /* bytes already in buffer */
  2187.  
  2188.           struct PacketBlock *worknode,
  2189.                              *nextnode;
  2190.  
  2191.           sh = (struct StreamHandle *)(dp -> dp_Arg1);
  2192.  
  2193.           worknode = (struct PacketBlock *)(sh -> sl -> sl_packetblocklist . mlh_Head);
  2194.  
  2195.           while( (nextnode = (struct PacketBlock *)(worknode -> node . mln_Succ)) && (read_size > 0UL) )
  2196.           {
  2197.             /* Find start block */
  2198.             if( (stream_offset <= (sh -> currpos)) &&
  2199.                 ((stream_offset + (worknode -> length)) > (sh -> currpos)) )
  2200.             {
  2201.               LONG cut          = ((sh -> currpos) - stream_offset),
  2202.                    curr_readlen = MIN( read_size, ((worknode -> length) - cut) );
  2203.  
  2204.               if( Seek( (sh -> sl -> sl_handle), ((worknode -> system_offset) + cut), OFFSET_BEGINNING ) == -1L )
  2205.               {
  2206.                 break;
  2207.               }
  2208.  
  2209.               /* We only need to check for a "complete fill" or failure, because the previous scan
  2210.                * (in the demuxer part) gurantees that the buffer (packet) has at least this ("curr_readlen") size
  2211.                */
  2212.               if( Read( (sh -> sl -> sl_handle), dest, curr_readlen ) != curr_readlen )
  2213.               {
  2214.                 error = IoErr();
  2215.                 break;
  2216.               }
  2217.  
  2218.               dest           += curr_readlen;
  2219.               read_size      -= curr_readlen;
  2220.               curr_read_size += curr_readlen;
  2221.               sh -> currpos  += curr_readlen;
  2222.  
  2223.               if( read_size < 0L )
  2224.               {
  2225.                 error = ERROR_BUFFER_OVERFLOW;
  2226.                 break;
  2227.               }
  2228.             }
  2229.  
  2230.             stream_offset += worknode -> length;
  2231.  
  2232.             worknode = nextnode;
  2233.           }
  2234.  
  2235.           dp -> dp_Res1 = ((error)?(-1L):(curr_read_size)); /* bytes read */
  2236.           dp -> dp_Res2 = error;                            /* result2    */
  2237.       }
  2238.           break;
  2239.  
  2240.       case ACTION_SEEK:
  2241.       {
  2242.           LONG newpos = 0L;
  2243.  
  2244.           sh = (struct StreamHandle *)(dp -> dp_Arg1);
  2245.  
  2246.           switch( dp -> dp_Arg3 )
  2247.           {
  2248.             case OFFSET_BEGINNING:
  2249.             {
  2250.                 newpos = dp -> dp_Arg2;
  2251.             }
  2252.                 break;
  2253.  
  2254.             case OFFSET_CURRENT:
  2255.             {
  2256.                 newpos += (sh -> currpos) + (dp -> dp_Arg2);
  2257.             }
  2258.                 break;
  2259.  
  2260.             case OFFSET_END:
  2261.             {
  2262.                 newpos += (sh -> sl -> sl_size) + (dp -> dp_Arg2);
  2263.             }
  2264.                 break;
  2265.  
  2266.             default: /* should return ERROR_SEEK_ERROR */
  2267.             {
  2268.                 newpos = -1L; /* forces ERROR_SEEK_ERROR by bounds check below */
  2269.             }
  2270.                 break;
  2271.           }
  2272.  
  2273.           /* Check bounds */
  2274.           if( (newpos > (sh -> sl -> sl_size)) || (newpos < 0L) )
  2275.           {
  2276.             dp -> dp_Res1  = -1L;
  2277.             dp -> dp_Res2  = ERROR_SEEK_ERROR;
  2278.           }
  2279.           else
  2280.           {
  2281.             dp -> dp_Res1  = sh -> currpos;
  2282.             dp -> dp_Res2  = 0L;
  2283.  
  2284.             sh -> currpos = newpos;
  2285.           }
  2286.       }
  2287.           break;
  2288.  
  2289.       case ACTION_COPY_DIR:
  2290.       {
  2291.           struct FileLock *src  = (struct FileLock *)BADDR( (dp -> dp_Arg1) ),
  2292.                           *dest;
  2293.  
  2294.           if( dest = (struct FileLock *)AllocVec( sizeof( struct FileLock ), MEMF_PUBLIC ) )
  2295.           {
  2296.             if( (LONG)src > 256L )
  2297.             {
  2298.               *dest = *src;
  2299.  
  2300.               msid -> Handler . OpenCount++;
  2301.             }
  2302.             else
  2303.             {
  2304.               LONG key = ((LONG)src / 16); /* src is now the index... */
  2305.  
  2306.               /* Does we have a system stream to work on ? */
  2307.               if( msid -> Demux . fd_demuxa[ key ] . sl_handle )
  2308.               {
  2309.                 dest -> fl_Link    = NULL;
  2310.                 dest -> fl_Key     = key;
  2311.                 dest -> fl_Access  = ACCESS_READ;
  2312.                 dest -> fl_Task    = (&(msid -> Handler . Process -> pr_MsgPort));
  2313.                 dest -> fl_Volume  = NULL;
  2314.  
  2315.                 msid -> Handler . OpenCount++;
  2316.               }
  2317.               else
  2318.               {
  2319.                 FreeVec( dest );
  2320.                 dest = NULL;
  2321.  
  2322.                 SetIoErr( ERROR_OBJECT_NOT_FOUND );
  2323.               }
  2324.             }
  2325.           }
  2326.  
  2327.           dp -> dp_Res1 = MKBADDR( dest );
  2328.           dp -> dp_Res2 = (dp -> dp_Res1)?(0L):(IoErr());
  2329.       }
  2330.           break;
  2331.  
  2332.       case ACTION_FREE_LOCK:
  2333.       {
  2334.           struct FileLock *fl = (struct FileLock *)BADDR( (dp -> dp_Arg1) );
  2335.  
  2336.           FreeLock( cb, msid, fl );
  2337.  
  2338.           dp -> dp_Res1 = DOSTRUE;
  2339.           dp -> dp_Res2 = 0L;
  2340.       }
  2341.           break;
  2342.  
  2343.       case ACTION_IS_FILESYSTEM:
  2344.       {
  2345.           dp -> dp_Res1 = DOSTRUE;  /* We are a filesystem */
  2346.           dp -> dp_Res2 = 0L;       /* Avoid Lock( ":", SHARED_LOCK ); overhead,
  2347.                                      * see Ralf Babel's "The Amiga GURU Book",
  2348.                                      * section 21.2.3.17, page 621
  2349.                                      */
  2350.       }
  2351.           break;
  2352.  
  2353.       case ACTION_EXAMINE_OBJECT:
  2354.       {
  2355.           struct FileLock      *fl             = (struct FileLock      *)BADDR( (dp -> dp_Arg1) );
  2356.           struct FileInfoBlock *fib            = (struct FileInfoBlock *)BADDR( (dp -> dp_Arg2) );
  2357.           LONG                  stream_index   = fl -> fl_Key;
  2358.           struct StreamList    *sl             = (&(msid -> Demux . fd_demuxa[ stream_index ]));
  2359.  
  2360.           dp -> dp_Res1 = ExamineFH( (sl -> sl_handle), fib );
  2361.  
  2362.           if( dp -> dp_Res1 )
  2363.           {
  2364.             TEXT buffer[ 256 ];
  2365.  
  2366.             mysprintf( cb, buffer, "%s@%ld", (fib -> fib_FileName), stream_index );
  2367.             stccpy( (fib -> fib_FileName), buffer, sizeof( (fib -> fib_FileName) ) );
  2368.  
  2369.             /* Set our stream size */
  2370.             fib -> fib_Size = sl -> sl_size;
  2371.  
  2372.             /* Bump number of blocks */
  2373.             fib -> fib_NumBlocks = INTDIVR( (sl -> sl_size), 1024UL ); /* BUG: Should be packet size to allow faster reading
  2374.                                                                         * in conjunction with async I/O
  2375.                                                                         */
  2376.  
  2377.             /* Convert to BCPL strings */
  2378.             STRPTR2BSTR( (fib -> fib_FileName) );
  2379.             STRPTR2BSTR( (fib -> fib_Comment)  );
  2380.  
  2381.             dp -> dp_Res2 = 0L;
  2382.           }
  2383.           else
  2384.           {
  2385.             dp -> dp_Res2 = IoErr();
  2386.           }
  2387.       }
  2388.           break;
  2389.  
  2390.       case ACTION_PARENT:
  2391.       {
  2392.           struct FileLock      *fl             = (struct FileLock *)BADDR( (dp -> dp_Arg1) );
  2393.           LONG                  stream_index   = fl -> fl_Key;
  2394.           struct StreamList    *sl             = (&(msid -> Demux . fd_demuxa[ stream_index ]));
  2395.  
  2396.           dp -> dp_Res1 = ParentOfFH( (sl -> sl_handle) ); /* Get parent of system stream */
  2397.           dp -> dp_Res2 = IoErr();
  2398.       }
  2399.           break;
  2400.  
  2401.       case ACTION_INFO: /* Required for async I/O */
  2402.       default:
  2403.       {
  2404.           dp -> dp_Res1 = DOSFALSE;
  2405.           dp -> dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  2406.       }
  2407.           break;
  2408.     }
  2409.  
  2410.     rport = dp -> dp_Port;
  2411.     dp -> dp_Port = (&(msid -> Handler . Process -> pr_MsgPort));
  2412.  
  2413.     PutMsg( rport, (dp -> dp_Link) );
  2414. }
  2415.  
  2416.  
  2417. /* Convert a C string into a BCPL string */
  2418. static
  2419. void STRPTR2BSTR( STRPTR s )
  2420. {
  2421.     size_t len = strlen( s );
  2422.  
  2423.     memmove( (&s[ 1 ]), s, len );
  2424.     s[ 0 ] = len; /* WARNING: Assumes that the string is less than < 255 bytes ! */
  2425. }
  2426.  
  2427.  
  2428. static
  2429. void FreeLock( struct ClassBase *cb, struct MPEGSystemInstData *msid, struct FileLock *fl )
  2430. {
  2431.     if( fl )
  2432.     {
  2433.       fl -> fl_Task = NULL; /* Any attempt to use the FileLock again should be DEADLY !! */
  2434.  
  2435.       msid -> Handler . OpenCount--;
  2436.  
  2437.       FreeVec( fl );
  2438.     }
  2439. }
  2440.  
  2441.  
  2442.  
  2443.